MIT 6.828 JOS Lab3 实验报告 您所在的位置:网站首页 general protection fault win7 MIT 6.828 JOS Lab3 实验报告

MIT 6.828 JOS Lab3 实验报告

2023-04-14 16:21| 来源: 网络整理| 查看: 265

本文使用 Zhihu On VSCode 创作并发布

前言

此为本人上本校的操作系统实习(实验班)时所写的实验报告,简单记述了JOS Lab的各个Exercise、Challenge(未覆盖所有Challenge,每个Lab大概做了1~3个Challenge)的基本思路。仅供有需者参考,上有关课程(比如本校的操统实习实验班)的最好不要直接抄。

附上源代码链接:https://github.com/Light-of-Hers/mit-jos

Exercise 1

在kern/pmap.c中加入:

////////////////////////////////////////////////////////////////////// // Make 'envs' point to an array of size 'NENV' of 'struct Env'. // LAB 3: Your code here. envs = (struct Env *) boot_alloc(NENV * sizeof(struct Env)); memset(envs, 0, NENV * sizeof(struct Env)); ////////////////////////////////////////////////////////////////////// // Map the 'envs' array read-only by the user at linear address UENVS // (ie. perm = PTE_U | PTE_P). // Permissions: // - the new image at UENVS -- kernel R, user R // - envs itself -- kernel RW, user NONE // LAB 3: Your code here. boot_map_region(kern_pgdir, UENVS, PTSIZE, PADDR(envs), PTE_U); Exercise 2env_init

按要求初始化各个PCB以及空闲链表。

void env_init(void) { // Set up envs array // LAB 3: Your code here. int i; struct Env *e; env_free_list = NULL; for (i = NENV - 1; i >= 0; --i) { e = &envs[i]; e->env_id = 0; e->env_status = ENV_FREE; e->env_link = env_free_list; env_free_list = e; } // Per-CPU part of the initialization env_init_percpu(); } env_setup_vm

复制内核页目录,并设置自映射。

static int env_setup_vm(struct Env *e) { struct PageInfo *pp = NULL; // Allocate a page for the page directory if (!(pp = page_alloc(ALLOC_ZERO))) return -E_NO_MEM; // Now, set e->env_pgdir and initialize the page directory. // LAB 3: Your code here. e->env_pgdir = page2kva(pp); pp->pp_ref += 1; for (size_t i = PDX(UTOP); i env_pgdir[i] = kern_pgdir[i]; // UVPT maps the env's own page table read-only. // Permissions: kernel R, user R e->env_pgdir[PDX(UVPT)] = PADDR(e->env_pgdir) | PTE_P | PTE_U; return 0; } region_alloc

按要求为进程的虚拟页分配对应的物理页即可。

static void region_alloc(struct Env *e, void *va, size_t len) { // LAB 3: Your code here. // (But only if you need it for load_icode.) uintptr_t vstart, vend; struct PageInfo *pp; int err; vstart = ROUNDDOWN((uintptr_t)va, PGSIZE); vend = ROUNDUP((uintptr_t)va + len, PGSIZE); for (; vstart env_pgdir, pp, (void*)vstart, PTE_W | PTE_U)) e_magic != ELF_MAGIC) panic("load_icode(1)"); ph = (struct Proghdr *) (binary + eh->e_phoff); ph_end = ph + eh->e_phnum; lcr3(PADDR(e->env_pgdir)); for (; ph p_type != ELF_PROG_LOAD) continue; if (ph->p_filesz > ph->p_memsz) panic("load_icode(2)"); region_alloc(e, (void*)ph->p_va, ph->p_memsz); memset((void*)ph->p_va, 0, ph->p_memsz); memcpy((void*)ph->p_va, binary + ph->p_offset, ph->p_filesz); } e->env_tf.tf_eip = eh->e_entry; // Now map one page for the program's initial stack // at virtual address USTACKTOP - PGSIZE. // LAB 3: Your code here. region_alloc(e, (void*)(USTACKTOP - PGSIZE), PGSIZE); lcr3(PADDR(kern_pgdir)); } env_create

分配一个PCB,加载程序,设置进程类型即可。

void env_create(uint8_t *binary, enum EnvType type) { // LAB 3: Your code here. struct Env *e; int err; if ((err = env_alloc(&e, 0)) env_type = ENV_TYPE_USER; } env_run

按要求设置curenv以及PCB的状态即可。

void env_run(struct Env *e) { // Step 1: If this is a context switch (a new environment is running): // 1. Set the current environment (if any) back to // ENV_RUNNABLE if it is ENV_RUNNING (think about // what other states it can be in), // 2. Set 'curenv' to the new environment, // 3. Set its status to ENV_RUNNING, // 4. Update its 'env_runs' counter, // 5. Use lcr3() to switch to its address space. // Step 2: Use env_pop_tf() to restore the environment's // registers and drop into user mode in the // environment. // LAB 3: Your code here. // panic("env_run not yet implemented"); if (curenv && curenv->env_status == ENV_RUNNING) curenv->env_status = ENV_RUNNABLE; curenv = e; curenv->env_status = ENV_RUNNING; curenv->env_runs += 1; lcr3(PADDR(curenv->env_pgdir)); env_pop_tf(&curenv->env_tf); } Exercise 4 & Challenge: Meta-Programmingkern/trapentry.inc

新建一个文件kern/trapentry.inc,列出以下各项。TH(n)表示不会产生error-code的第n号中断的trap handler;THE(n)表示会产生error-code的第n号中断的trap handler。

TH(0) TH(1) TH(2) TH(3) TH(4) TH(5) TH(6) TH(7) THE(8) THE(10) THE(11) THE(12) THE(13) THE(14) TH(16) THE(17) TH(18) TH(19) TH(48) kern/trapentry.S

在kern/trapentry.S中定义TH和THE,引入kern/trapentry.inc,构成各个中断处理例程:

#define TH(n) \ TRAPHANDLER_NOEC(handler##n, n) #define THE(n) \ TRAPHANDLER(handler##n, n) .text /* * Lab 3: Your code here for generating entry points for the different traps. */ #include _alltraps

先补齐trapframe所需要的信息,更改段寄存器,接着将ESP压栈作为参数struct Trapframe* tf并调用trap函数。

/* * Lab 3: Your code here for _alltraps */ _alltraps: pushl %ds pushl %es pushal movw $GD_KD, %ax movw %ax, %ds movw %ax, %es pushl %esp call trap trap_spin: jmp trap_spin kern/trap.c

在kern/trap.c中定义TH和THE,引入kern/trapentry.inc,构成中断向量表:

#define TH(n) extern void handler##n (void); #define THE(n) TH(n) #include #undef THE #undef TH #define TH(n) [n] = handler##n, #define THE(n) TH(n) static void (* handlers[256])(void) = { #include }; #undef THE #undef TH trap_init

考虑到处理的方便,将所有的中断向量都设为中断门,也就是处理过程中屏蔽外部中断。

void trap_init(void) { extern struct Segdesc gdt[]; // LAB 3: Your code here. for (int i = 0; i


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有